"""
    Creates and manages a sqlite database which is used to configure the web_stats program.
    This decoupling allows multiple web logs to be managed from a single location and
    because it uses SqlAlchemy a range of different database backends. Currently, the backend is
    is tested with sqlite and mysql.
"""

import os
from sqlalchemy import create_engine
from sqlalchemy import Table, Column, Integer, String, MetaData
from sqlalchemy.orm import sessionmaker,mapper

class Configuration(object):
    """
        Manages a database configuration for log files. Sets up a database, gets entry, and adds entries to the database
    """
    def __init__(self,log_file_path,
                 db_connection_string,
                 delimiter, 
                 position_request_date_time, 
                 position_client_ip, 
                 position_request_url, 
                 position_http_response_code, 
                 position_size_bytes,
                 position_response_time_secs, 
                 position_domain_name=None, 
                 position_referer=None, 
                 position_user_agent=None, 
                 position_user_name=None,
                 log_rotated_file_path=None,
                 log_rotated_uid=None
                 ):
        
        self.log_file_path = log_file_path
        self.db_connection_string = db_connection_string
        self.delimiter = delimiter
        self.position_request_date_time = position_request_date_time
        self.position_client_ip = position_client_ip
        self.position_request_url = position_request_url
        self.position_http_response_code = position_http_response_code
        self.position_size_bytes = position_size_bytes
        self.position_response_time_secs = position_response_time_secs
        self.position_domain_name = position_domain_name 
        self.position_referer = position_referer 
        self.position_user_agent = position_user_agent 
        self.position_user_name = position_user_name
        self.log_rotated_file_path  = log_rotated_file_path
        self.log_rotated_uid = log_rotated_uid
        
    def __repr__(self):
        return "<%s, %s, %s, '%s'>" % (self.id, self.log_file_path,self.db_connection_string,self.delimiter)

class WebStatsConfigure(object):
    def __init__(self,db_file):
        try:
            self.db_file_full_path = os.path.abspath("./") + os.path.sep + db_file
            self.engine = create_engine(("sqlite:///" + self.db_file_full_path))
        except IOError:
            raise
        
        self.Session = sessionmaker(bind = self.engine, autoflush = True)
        self.session = self.Session()
        self.metadata = MetaData()
        
        self.configuration_table = Table("configuration",self.metadata,
                               Column('id',Integer,primary_key = True),
                               Column('log_file_path',String(1023)),
                               Column('db_connection_string',String(1023)),
                               Column('delimiter',String(255)),
                               Column('position_request_date_time',Integer),
                               Column('position_client_ip',Integer),
                               Column('position_request_url',Integer),
                               Column('position_http_response_code',Integer),
                               Column('position_size_bytes',Integer),
                               Column('position_response_time_secs',Integer),
                               Column('position_domain_name',Integer),
                               Column('position_referer',Integer),
                               Column('position_user_agent',Integer),
                               Column('position_user_name',Integer),
                               Column('log_rotated_file_path',String(1023)),
                               Column('log_rotated_uid',String(255)))
        self.metadata.create_all(self.engine)
        try:
            mapper(Configuration,self.configuration_table)
        except:
            pass
        
    def clean(self):
        self.engine.dispose()
        if os.path.isfile(self.db_file_full_path):
            os.remove(self.db_file_full_path)
    
    def add(self,log_file_path, db_connection_string, delimiter, position_request_date_time, position_client_ip, position_request_url, position_http_response_code, position_request_byte_size, position_response_time_secs=None, position_domain_name=None, position_referer=None, position_user_agent=None, position_user_name=None,log_rotated_file_path=None,log_rotated_uid=None):
        """
            Add log file configuration into a database
            Usage: my_conf_obj.add(db_connection_string, delimiter, position_request_date_time, position_client_ip, position_request_url, position_http_response_code, position_request_byte_size,position_response_time_secs)
        """
        session = self.Session()
        new_configuration = Configuration(log_file_path, db_connection_string, delimiter, 
                                          position_request_date_time, 
                                          position_client_ip, 
                                          position_request_url, 
                                          position_http_response_code, 
                                          position_request_byte_size, 
                                          position_response_time_secs,
                                          position_domain_name,
                                          position_referer,
                                          position_user_agent,
                                          position_user_name,
                                          log_rotated_file_path,
                                          log_rotated_uid)
        self.session.add(new_configuration)
        self.session.commit()
        
    def get_hash(self,id):
        """Return a hash back of values of a single configuration"""
        configuration = self.session.query(Configuration).get(id)
        c = configuration # Make the code easier to read
        if c != None:
            return {"log_file_path": c.log_file_path,"db_connection_string": c.db_connection_string,"delimiter" : c.delimiter, 
                                           "log_rotated_file_path" : c.log_rotated_file_path,"log_rotated_uid" : c.log_rotated_uid,
                    "positions_in_log" : {"request_date_time" : c.position_request_date_time, "client_ip" : c.position_client_ip, "request_url" : c.position_request_url,
                                          "http_response_code" : c.position_http_response_code,"size_bytes" : c.position_size_bytes,
                                          "request_response_time_secs" : c.position_response_time_secs, "domain_name" : "c.position_domain_name","referer" : c.position_referer,
                                          "domain_name" : c.position_domain_name, "user_agent" : c.position_user_agent, "user_name" : c.position_user_name}}  
        else:
            return None
    
    def get_all(self):
        configurations = self.session.query(Configuration).from_statement("select * from configuration").all()
        return configurations
    
    def get(self,id):
        configuration = self.session.query(Configuration).get(id)
        return configuration
    
    def set(self,id,properties_hash):
        config = self.get(id)
        properties = properties_hash.keys()
        for prop in properties:
            try:
                config.__setattr__(prop,properties_hash[prop])
            except AttributeError:
                print "Attribute %s is not defined" % prop
                raise
        self.session.commit()
        
    def delete(self,id):
        config = self.get(id)
        self.session.delete(config)
        self.session.commit()
        
if __name__ == "__main__":
    WebStatsConfigure("configure_web_stats.db3")

    
